package cnholiday

import (
	"time"

	"github.com/dromara/carbon/v2"
)

// 节假日支持，计算工作日和法定节假日

type TimeRegion struct {
	Start carbon.Carbon
	End   carbon.Carbon
}

var LawHolidays = map[int][]TimeRegion{
	2025: {
		{Start: carbon.Parse("2025-01-01"), End: carbon.Parse("2025-01-01")}, // 元旦
		{Start: carbon.Parse("2025-01-28"), End: carbon.Parse("2025-02-04")}, // 春节
		{Start: carbon.Parse("2025-04-04"), End: carbon.Parse("2025-04-06")}, // 清明
		{Start: carbon.Parse("2025-05-01"), End: carbon.Parse("2025-05-05")}, // 五一
		{Start: carbon.Parse("2025-05-31"), End: carbon.Parse("2025-06-02")}, // 端午
		{Start: carbon.Parse("2025-10-01"), End: carbon.Parse("2025-10-08")}, // 国庆中秋
	},
	2024: {
		{Start: carbon.Parse("2024-01-01"), End: carbon.Parse("2024-01-01")}, // 元旦
		{Start: carbon.Parse("2024-02-10"), End: carbon.Parse("2024-02-17")}, // 新年
		{Start: carbon.Parse("2024-04-04"), End: carbon.Parse("2024-04-06")}, // 清明
		{Start: carbon.Parse("2024-05-01"), End: carbon.Parse("2024-05-05")}, // 五一
		{Start: carbon.Parse("2024-06-08"), End: carbon.Parse("2024-06-10")}, // 端午
		{Start: carbon.Parse("2024-09-15"), End: carbon.Parse("2024-09-17")}, // 中秋
		{Start: carbon.Parse("2024-10-01"), End: carbon.Parse("2024-10-07")}, // 国庆
	},
	2023: {
		{Start: carbon.Parse("2023-01-01"), End: carbon.Parse("2023-01-02")}, // 元旦
		{Start: carbon.Parse("2023-01-21"), End: carbon.Parse("2023-01-27")}, // 新年
		{Start: carbon.Parse("2023-04-05"), End: carbon.Parse("2023-04-05")}, // 清明
		{Start: carbon.Parse("2023-04-29"), End: carbon.Parse("2023-05-03")}, // 五一
		{Start: carbon.Parse("2023-06-22"), End: carbon.Parse("2023-06-24")}, // 端午
		{Start: carbon.Parse("2023-09-29"), End: carbon.Parse("2023-10-06")}, // 中秋 + 国庆
		{Start: carbon.Parse("2023-12-30"), End: carbon.Parse("2023-12-31")}, // 元旦
	},
	2022: {
		{Start: carbon.Parse("2022-01-01"), End: carbon.Parse("2022-01-03")}, // 元旦
		{Start: carbon.Parse("2022-01-31"), End: carbon.Parse("2022-02-06")}, // 新年
		{Start: carbon.Parse("2022-04-03"), End: carbon.Parse("2022-04-05")}, // 清明
		{Start: carbon.Parse("2022-04-30"), End: carbon.Parse("2022-05-04")}, // 五一
		{Start: carbon.Parse("2022-06-03"), End: carbon.Parse("2022-06-05")}, // 端午
		{Start: carbon.Parse("2022-09-10"), End: carbon.Parse("2022-09-12")}, // 中秋
		{Start: carbon.Parse("2022-10-01"), End: carbon.Parse("2022-10-07")}, // 国庆
	},
}

// 调班
var AdjustWorkdays = map[int][]carbon.Carbon{
	2025: {
		carbon.Parse("2025-01-26"), carbon.Parse("2025-02-08"), carbon.Parse("2025-04-27"),
		carbon.Parse("2025-09-28"), carbon.Parse("2025-10-11"),
	},
	2024: {
		carbon.Parse("2024-02-04"), carbon.Parse("2024-02-18"), carbon.Parse("2024-04-07"),
		carbon.Parse("2024-04-28"), carbon.Parse("2024-05-11"), carbon.Parse("2024-09-14"),
		carbon.Parse("2024-09-29"), carbon.Parse("2024-10-12"),
	},
	2023: {
		carbon.Parse("2024-01-28"), carbon.Parse("2024-01-29"), carbon.Parse("2024-04-23"),
		carbon.Parse("2024-05-06"), carbon.Parse("2024-06-25"), carbon.Parse("2024-10-07"),
		carbon.Parse("2024-10-08"),
	},
	2022: {
		carbon.Parse("2024-01-29"), carbon.Parse("2024-01-30"), carbon.Parse("2024-04-02"),
		carbon.Parse("2024-04-24"), carbon.Parse("2024-05-07"), carbon.Parse("2024-10-08"),
		carbon.Parse("2024-10-09"),
	},
}

func IsHoliday(t carbon.Carbon) bool {
	year := t.Year()
	for _, region := range LawHolidays[year] {
		if region.Start.Eq(t) {
			return true
		}
		if region.End.Eq(t) {
			return true
		}
		if region.Start.Lt(t) && region.End.Gt(t) {
			return true
		}
	}
	weekday := t.StdTime().Weekday()
	if weekday == time.Saturday || weekday == time.Sunday {
		// 如果在调班里
		for _, d := range AdjustWorkdays[year] {
			if d.Eq(t) {
				return false
			}
		}
		return true
	}
	return false
}

func IsHoliday2(t time.Time) bool {
	c := carbon.CreateFromStdTime(t, time.Local.String())
	return IsHoliday(c)
}

func IsWorkday(t carbon.Carbon) bool {
	return !IsHoliday(t)
}

func IsWorkday2(t time.Time) bool {
	c := carbon.CreateFromStdTime(t, time.Local.String())
	return IsWorkday(c)
}

func GetHolidays(start carbon.Carbon, end carbon.Carbon) []carbon.Carbon {
	var dates []carbon.Carbon
	if start.Gt(end) {
		panic("start can not be after of end")
	}
	for t := start; t.Lt(end); t = t.AddDays(1) {
		if IsHoliday(t) {
			dates = append(dates, t)
		}
	}
	return dates
}

func GetHolidays2(start time.Time, end time.Time) []time.Time {
	var dates []time.Time
	if start.After(end) {
		panic("start can not be after of end")
	}
	for t := start; !t.After(end); t = t.AddDate(0, 0, 1) {
		if IsHoliday2(t) {
			dates = append(dates, t)
		}
	}
	return dates
}

func GetWorkdays(start carbon.Carbon, end carbon.Carbon) []carbon.Carbon {
	var dates []carbon.Carbon
	if start.Gt(end) {
		panic("start can not be after of end")
	}
	end = carbon.CreateFromDate(end.Year(), int(end.Month()), end.Day()).Tomorrow()
	for t := start; t.Lt(end); t = t.AddDays(1) {
		if IsWorkday(t) {
			dates = append(dates, t)
		}
	}
	return dates
}

func GetWorkdays2(start time.Time, end time.Time) []time.Time {
	var dates []time.Time
	if start.After(end) {
		panic("start can not be after of end")
	}
	end = time.Date(end.Year(), end.Month(), end.Day(), 23, 59, 59, 0, time.Local)
	for t := start; !t.After(end); t = t.AddDate(0, 0, 1) {
		if IsWorkday2(t) {
			dates = append(dates, t)
		}
	}
	return dates
}
